﻿using System;
using System.Windows.Forms;
using System.Xml;
using SdmxMl.Common;
using SdmxMl.Helper;
using SdmxMl.Manager;
using SdmxMl.Panels;
using SdmxMl.Structure;

namespace SdmxMl.UC
{
    /// <summary>
    /// User control for Metadata Report and associated attributes.
    /// </summary>
    public partial class UcReportStructure : UserControl, IUrnSelect
    {
        #region Internal Members

        private PanelAnnotationList pannelAnnot;
        private ReportStructureType _report;
        private BaseArtefact baseArtefact;
        private UcMlText ucMlText = null;
        private TreeNode rootNode;
        private UcTextFormat ucTextFormat = null;
        private TreeNavigation treeNavigate;
        private bool _isFinal;
        private MetadataAttributeType meta;

        private ConceptSchemeReference lastSchemeUsed;
        private string suggestedConceptId;

        #endregion //Internal Members

        #region Construction

        public UcReportStructure()
        {
            InitializeComponent();
            treeNavigate = new TreeNavigation();
            treeNavigate.TreeSdmx = treeViewH;
            treeNavigate.RecordNavButtons(toolStripButtonPrevSel, toolStripButtonNextSelection, toolStripButtonNavParent, toolStripComboBoxHistory);

            ucMlText = new UcMlText();
            customComboBoxName.DropDownControl = ucMlText;
            ucTextFormat = new UcTextFormat();
            customComboBoxTextType.DropDownControl = ucTextFormat;


            ucConceptRef1.ConceptSelect += new EventHandler(ucConceptRef1_ConceptSelect);
        }


        #endregion // Construction

        #region Binding

        public bool BindFromNode(TreeNode node, PanelAnnotationList panelAnnotation, bool isFinal)
        {
            _isFinal = isFinal;
            pannelAnnot = panelAnnotation;
            _report = null;
            if (node != null)
                _report = node.Tag as ReportStructureType;
            baseArtefact = _report;
            
            BindToControls();

            PrepareSuggestedConceptReference(null);

            return this.Visible;
        }

        private void PrepareSuggestedConceptReference(MetadataAttributeType currentMeta)
        {
            bool getFirst = false;
            suggestedConceptId = null;

            //If meta is null try to get it from current report
            if (currentMeta == null)
            {
                if (_report != null && _report.MetadataAttributeList.Count > 0)
                    currentMeta = _report.MetadataAttributeList[_report.MetadataAttributeList.Count - 1];
                getFirst = true;
            }
            if (currentMeta != null)
            {
                lastSchemeUsed = currentMeta.ConceptSchemeInfo;
                if (lastSchemeUsed.IsFilled)
                {
                    // try to get conceptscheme
                    ConceptSchemeType cst = ReferenceManager.LocateConceptScheme(lastSchemeUsed);
                    if (cst != null && cst.ConceptList.Count > 0)
                    {
                        if (getFirst == false)
                        {
                            ISdmxHierarchyListItem item = cst.ConceptList.LocateItem(currentMeta.ConceptInfo.Id);
                            if (item != null)
                            {
                                int index = cst.ConceptList.IndexOf(item);
                                if (index+1 < cst.ConceptList.Count)
                                    suggestedConceptId = cst.ConceptList[index+1].Id;
                            }
                        }

                        if (suggestedConceptId == null)
                            suggestedConceptId = cst.ConceptList[0].Id;
                    }
                }
            }
        }

        public bool UpdateNodeTag(TreeNode node)
        {
            bool err = false;
            if (node != null)
            {
                err = BindFromControls();
                if (_report != null && node.Text != _report.ToString())
                    node.Text = _report.ToString();
            }

            return false; // true on error
        }

        private void BindToControls()
        {
            treeViewH.Nodes.Clear();
            groupBoxMetaAttrib.Visible = false;
            if (baseArtefact != null)
            {
                Visible = true;

                // Info tab
                textBoxId.Text = _report.Id;


                // Target ref, fill target identifiers combo
                MetadataStructureDefinitionType _msd = _report.Msd;

                comboBoxTargetRef.Items.Clear();
                if (_msd != null)
                {
                    // Propose target identifiers and partial list
                    comboBoxTargetRef.Items.Add(_msd.TargetIdentifiers.FullTargetIdentifier.Id);
                    foreach (PartialTargetIdentifierType pti in _msd.TargetIdentifiers.PartialTargetIdentifierList)
                        comboBoxTargetRef.Items.Add(pti.Id);

                    if (_report.TargetId == null || _report.TargetId.Length == 0)
                        _report.TargetId = _msd.TargetIdentifiers.FullTargetIdentifier.Id;
                }
                
                comboBoxTargetRef.Text = _report.TargetId;

                textBoxUrn.Text = _report.Urn;
                textBoxUri.Text = _report.Uri;
                customComboBoxName.Text = _report.Name.ToString();
                ucMlText.ML = _report.Name;
                comboMultiLinesDescr.Text = _report.Description.ToString();
                comboMultiLinesDescr.ML = _report.Description;

                // Meta attributes tab
                rootNode = new TreeNode(baseArtefact.ToString());
                rootNode.Tag = baseArtefact;
                ConstructTreeHierarchy(meta);

                UpdateAnnotation();
                IsFinalEditControls(_isFinal);
            }
            else
                Visible = false;
        }

        // Manage Edition possibility
        private void IsFinalEditControls(bool isFinal)
        {
            bool enabled = isFinal == false;

            // Info Tab
            textBoxId.ReadOnly = isFinal;
            comboBoxTargetRef.Enabled = enabled;
            textBoxUri.ReadOnly = isFinal;
            textBoxUrn.ReadOnly = isFinal;
            customComboBoxName.IsFinal = isFinal;
            comboMultiLinesDescr.IsFinal = isFinal;
            if (ucTextFormat.TF != null)
                ucTextFormat.IsFinal = isFinal;

            // Meta Attrib

            // ToolStrip Bar
            toolStripButtonDelCodeRef.Enabled = enabled;
            toolStripButtonNewCode.Enabled = enabled;
            toolStripButtonNewChild.Enabled = enabled;
        }

        private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateAnnotation();
        }


        private void UpdateAnnotation()
        {
            if (tabControl.SelectedIndex == 0)
                pannelAnnot.BindFromNode(baseArtefact, _isFinal);
            else if (tabControl.SelectedIndex == 1)
                pannelAnnot.BindFromNode(meta, _isFinal);
        }

        protected bool BindFromControls()
        {
            bool err = false;
            if (baseArtefact != null)
            {

                // Info page
                _report.Id = textBoxId.Text;
                _report.Urn = textBoxUrn.Text;
                _report.Uri = textBoxUri.Text;
                _report.TargetId = comboBoxTargetRef.Text;
                _report.Name.UpdateForCurrentLanguage(customComboBoxName.Text);
                _report.Description.UpdateForCurrentLanguage(comboMultiLinesDescr.Text);

                // Refresh textformat of selected item in tree (if any)
                if (meta != null)
                    meta.TextFormat = ucTextFormat.TF;

            }
            return err;
        }

        #endregion //Binding

        #region Tree Construct & Update

        private void ConstructTreeHierarchy(object nodeTagToSelect)
        {
            treeViewH.DrawMode = TreeViewDrawMode.Normal;
            treeViewH.BeginUpdate();
            rootNode.Nodes.Clear();
            treeViewH.Nodes.Clear();
            _report.MetadataAttributeList.GetTreeHierarchyAsNodes(rootNode);

            treeViewH.Nodes.Add(rootNode);
            rootNode.Expand();

            UpdateTreeIcons(rootNode);

            treeViewH.EndUpdate();

            // Retrieve previously selected if any
            TreeNode targetNode = null;
            TreeHelper.LocateObject(treeViewH, nodeTagToSelect, ref targetNode);
            if (targetNode != null)
            {
                treeViewH.SelectedNode = targetNode;
                treeViewH.SelectedNode.EnsureVisible();
            }
            else
            {
                if (rootNode.Nodes.Count > 0)
                {
                    treeViewH.SelectedNode = rootNode.Nodes[0];
                    treeViewH.SelectedNode.EnsureVisible();
                }
            }
            treeNavigate.Reset();
            treeViewH.DrawMode = TreeViewDrawMode.OwnerDrawText;

        }

        private void UpdateTreeIcons(TreeNode node)
        {
            MetadataAttributeType metaAtt = node.Tag as MetadataAttributeType;

            if (node == rootNode)
                node.ImageKey = node.SelectedImageKey = "dirTree";
            else
                SetMetaIcon(node, metaAtt);

            foreach (TreeNode nd in node.Nodes)
                UpdateTreeIcons(nd);

        }

        private void SetMetaIcon(TreeNode node, MetadataAttributeType metaAtt)
        {
            if (metaAtt != null && metaAtt.UsageStatus == UsageStatusType.Mandatory)
                node.ImageKey = node.SelectedImageKey = "requiredInfo";
            else
                node.ImageKey = node.SelectedImageKey = "optionalInfo";

        }

        void ucConceptRef1_ConceptSelect(object sender, EventArgs e)
        {
            TreeNode nd = treeViewH.SelectedNode;
            if (nd != null)
            {
                numTextBoxID.Text = ucConceptRef1.ConceptName;
                if (nd.Text != nd.Tag.ToString())
                    nd.Text = nd.Tag.ToString();
            }
        }


        private void UpdateControlsFromTreeSelected()
        {
            meta = null;
            if (treeViewH.SelectedNode != null)
            {
                groupBoxMetaAttrib.Visible = true;
                meta = treeViewH.SelectedNode.Tag as MetadataAttributeType;
                if (meta != null)
                {
                    numTextBoxID.Text = meta.Id;
                    customComboBoxTextType.Text = meta.TextFormat.ToString();
                    ucTextFormat.TF = meta.TextFormat;

                    ucConceptRef1.BindRef(meta.ConceptSchemeInfo, meta.ConceptInfo);

                    ucCodelistRef.BindRef(meta.RepresentationInfo);

                    ucMetaOccurence.BindMetaOccurences(meta.MetaOccurence, _isFinal);
                    checkBoxMultiCode.Checked = meta.MetaOccurence.IsMultiCodes;
                    checkBoxMultiCode.Enabled = _isFinal == false;
                }
            }
            if (meta == null)
                groupBoxMetaAttrib.Visible = false;

        }
        #endregion

        #region Tree Events

        // Retrieve updated code info
        private void treeViewH_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            TreeNode nd = treeViewH.SelectedNode;
            if (nd != null)
            {
                if (nd.Text != nd.Tag.ToString())
                    nd.Text = nd.Tag.ToString();


                meta = treeViewH.SelectedNode.Tag as MetadataAttributeType;
                if (meta != null)
                {
                    meta.Id = numTextBoxID.Text;
                    meta.TextFormat = ucTextFormat.TF;
                    ucMetaOccurence.UpdateOccurenceValues();
                    meta.MetaOccurence.IsMultiCodes = checkBoxMultiCode.Checked;

                    // Refresh icon in case of change
                    SetMetaIcon(treeViewH.SelectedNode, meta);
                }
            }
        }

        private void treeViewH_AfterSelect(object sender, TreeViewEventArgs e)
        {
            UpdateControlsFromTreeSelected();

            UpdateAnnotation();
        
            DisplayInfo(TreeHelper.CalculateNodeChilds(treeViewH.SelectedNode));
        }

        // Info in status bar
        public void DisplayInfo(string msg)
        {
            if (msg != null)
                labelStatusInfo.Text = msg;
        }


        private void treeViewH_AfterNodeMove(object sender, MoveableTreeView.AfterNodeMoveEventArgs e)
        {
            if (e != null)
            {
                // The parent meta attribute collection is to be rearanged
                MetadataAttributeType metaParent = e.MovedNode.Parent.Tag as MetadataAttributeType;
                MetadataAttributeTypeList list = null;
                if (metaParent == null)
                    list = _report.MetadataAttributeList;
                else
                    list = metaParent.MetadataAttributeList;

                MetadataAttributeType metaMoved = e.MovedNode.Tag as MetadataAttributeType;
                list.Remove(metaMoved);
                list.Insert(e.NewIndex, metaMoved);
            }
        }

        #endregion // Tree Events


        #region ToolStripHierarchy

        private void toolStripButtonNewCode_Click(object sender, EventArgs e)
        {
            if (treeViewH.SelectedNode != null)
            {
                //prepare id for concept scheme used
                PrepareSuggestedConceptReference(treeViewH.SelectedNode.Tag as MetadataAttributeType);

                try
                {
                    MetadataAttributeTypeList metaList = null;
                    MetadataAttributeType metaNew = new MetadataAttributeType();
                    if (suggestedConceptId != null)
                    {
                        metaNew.ConceptSchemeInfo.UpdateRef(lastSchemeUsed);
                        metaNew.ConceptInfo.Id = suggestedConceptId;
                    }
                    else
                    {
                        metaNew.ConceptInfo.Id = "Undefined";
                    }

                    // update tree also                
                    TreeNode tn = new TreeNode(metaNew.ToString());
                    tn.Tag = metaNew;

                    // do we Add as child or not 
                    bool asChild = treeViewH.SelectedNode == treeViewH.Nodes[0] || sender == toolStripButtonNewChild;
                    if (asChild)
                    {
                        metaList = treeViewH.SelectedNode == treeViewH.Nodes[0] ?
                            _report.MetadataAttributeList : (treeViewH.SelectedNode.Tag as MetadataAttributeType).MetadataAttributeList;
                        metaList.Add(metaNew);

                        treeViewH.SelectedNode.Nodes.Add(tn);
                    }
                    else
                    {
                        metaList = treeViewH.SelectedNode.Parent == null || treeViewH.SelectedNode.Parent == treeViewH.Nodes[0] ? 
                            _report.MetadataAttributeList : (treeViewH.SelectedNode.Parent.Tag as MetadataAttributeType).MetadataAttributeList;

                        if (metaList.Count > 0)
                        {
                            int index = metaList.IndexOf(treeViewH.SelectedNode.Tag as MetadataAttributeType);
                            if (metaList.Count > index + 1)
                            {
                                metaList.Insert(index+1, metaNew);
                                index = treeViewH.SelectedNode.Parent.Nodes.IndexOf(treeViewH.SelectedNode);
                                treeViewH.SelectedNode.Parent.Nodes.Insert(index+1, tn);
                            }
                            else
                            {
                                metaList.Add(metaNew);
                                treeViewH.SelectedNode.Parent.Nodes.Add(tn);
                           }
                        }
                        else
                        {
                            metaList.Add(metaNew);
                            treeViewH.SelectedNode.Parent.Nodes.Add(tn);
                        }
                    }

                    // update selection in tree                
                    treeViewH.SelectedNode = tn;
                    SetMetaIcon(treeViewH.SelectedNode, metaNew);
                }
                catch
                {
                    MessageBox.Show("Error occured during reference creation");
                }
            }
        }

        private void toolStripButtonDelCodeRef_Click(object sender, EventArgs e)
        {
            if (treeViewH.SelectedNode != null && treeViewH.SelectedNode != rootNode)
            {
                if (MessageBox.Show("Delete selected item and its childs?", "Check",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    // Determines nodes to locate after deletion
                    
                    TreeNode nodeToSelect = treeViewH.SelectedNode.Parent;
                    if (nodeToSelect.Nodes.IndexOf(treeViewH.SelectedNode) > 0)
                        nodeToSelect = nodeToSelect.Nodes[nodeToSelect.Nodes.IndexOf(treeViewH.SelectedNode) - 1];
                    else if (nodeToSelect.Nodes.Count > 1)
                        nodeToSelect = nodeToSelect.Nodes[nodeToSelect.Nodes.IndexOf(treeViewH.SelectedNode) + 1];
                                         
                    if (_report.MetadataAttributeList.DeleteRefcode(treeViewH.SelectedNode.Tag as MetadataAttributeType))
                    {
                        // Redraw tree & locate
                        ConstructTreeHierarchy(nodeToSelect.Tag);
                    }
                    
                }
            }
        }

        private void toolStripButtonExpandCollapse_Click(object sender, EventArgs e)
        {
            if (treeViewH.SelectedNode != null)
            {   // update meta
                treeViewH_BeforeSelect(this, null);

                TreeHelper.toolStripButtonExpandCollapse(treeViewH);
                // Update as event locked
                treeViewH_AfterSelect(this, new TreeViewEventArgs(treeViewH.SelectedNode));
            }
        }


        #endregion // ToolStripHierarchy

        #region Edit Controls Events

        private void textBoxId_Leave(object sender, EventArgs e)
        {
            // Refresh immediatly the Id
            if (_report != null && treeViewH.Nodes.Count > 0)
            {
                _report.Id = textBoxId.Text;
                if (treeViewH.Nodes[0].Text != _report.Id)
                    treeViewH.Nodes[0].Text = _report.Id;

            }
        }

        private void customComboBoxTextType_DropDownClosed(object sender, EventArgs e)
        {
            if (meta != null)
                customComboBoxTextType.Text = meta.TextFormat.ToString();
        }


        private void comboBoxUsage_SelectedIndexChanged(object sender, EventArgs e)
        {
            // TODO update Icon

                SetMetaIcon(treeViewH.SelectedNode, meta);
        }

        #endregion //Edit Controls Events



        private void BReportConcept(XmlTextWriter xw, int level, ISdmxArtefactRef arSchemeRef, string conceptId)
        {
            ConceptSchemeType cst = ReferenceManager.LocateConceptScheme(arSchemeRef);
            ConceptType c = null;

            if (cst != null)
                c = cst.ConceptList.LocateItem(conceptId) as ConceptType;

            if (c != null)
            {
                xw.WriteStartElement("Concept");
                xw.WriteElementString("Id", c.Id);
                xw.WriteElementString("Level", level.ToString());
                xw.WriteElementString("Name", c.Name.ToString());
                xw.WriteElementString("Context", c.ContextInfo);
                xw.WriteEndElement();
            }
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            try
            {
                XmlTextWriter xw = new XmlTextWriter("C:\\RPT_" + _report.Id + ".xml", System.Text.Encoding.UTF8);
                xw.Formatting = Formatting.Indented;
                xw.WriteStartElement("Report");
                treeReport(xw, this.treeViewH.Nodes[0]);
                xw.WriteEndElement();
                xw.Close();
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Report Concepts Write", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void treeReport(XmlTextWriter xw, TreeNode tn)
        {
            MetadataAttributeType meta = tn.Tag as MetadataAttributeType;
            if (meta != null)
                BReportConcept(xw, tn.Level, meta.ConceptSchemeInfo, meta.ConceptInfo.Id);

            foreach (TreeNode node in tn.Nodes)
                treeReport(xw, node);


        }

        private void checkBoxMultiCode_CheckedChanged(object sender, EventArgs e)
        {

        }


        #region IUrnSelect Members

        public void SelectItem(UrnParser up)
        {
            if (_report != null && up != null && up.ArType == SdmxMl.Manager.SdmxArtefactType.MetadataStructureDefinitions)
            {
                string[] arr = up.SubTypeId.Split('.');
                if (up.SubType == "ReportStructure" && arr.Length > 1 && arr[0] == _report.Id)
                {
                    // locate submitted concept
                    MetadataAttributeType m = _report.MetadataAttributeList.GetAttributeReferingConcept(arr[1]);
                    if (m != null)
                    {
                        // Ensure tab selection
                        this.tabControl.SelectedIndex = 1;

                        // Retrieve previously selected if any
                        TreeNode targetNode = null;
                        TreeHelper.LocateObject(treeViewH, m, ref targetNode);
                        if (targetNode != null)
                        {
                            treeViewH.SelectedNode = targetNode;
                            treeViewH.SelectedNode.EnsureVisible();
                        }
                   }
                }
            }
        }

        #endregion

    }
}
